home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / bash_114.zip / bash-1.14.2 / trap.c < prev    next >
C/C++ Source or Header  |  1994-06-26  |  16KB  |  616 lines

  1. /* trap.c -- Not the trap command, but useful functions for manipulating
  2.    those objects.  The trap command is in builtins/trap.def. */
  3.  
  4. /* Copyright (C) 1987, 1991 Free Software Foundation, Inc.
  5.  
  6.    This file is part of GNU Bash, the Bourne Again SHell.
  7.  
  8.    Bash is free software; you can redistribute it and/or modify it under
  9.    the terms of the GNU General Public License as published by the Free
  10.    Software Foundation; either version 1, or (at your option) any later
  11.    version.
  12.  
  13.    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  14.    WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15.    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16.    for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License along
  19.    with Bash; see the file COPYING.  If not, write to the Free Software
  20.    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  21.  
  22. #include <stdio.h>
  23.  
  24. #include "bashtypes.h"
  25. #include "trap.h"
  26.  
  27. #if defined (HAVE_STRING_H)
  28. #  include <string.h>
  29. #else /* !HAVE_STRING_H */
  30. #  include <strings.h>
  31. #endif /* !HAVE_STRING_H */
  32.  
  33. #include "shell.h"
  34. #include "signames.h"
  35.  
  36. /* Flags which describe the current handling state of a signal. */
  37. #define SIG_INHERITED   0x0    /* Value inherited from parent. */
  38. #define SIG_TRAPPED     0x1    /* Currently trapped. */
  39. #define SIG_HARD_IGNORE 0x2    /* Signal was ignored on shell entry. */
  40. #define SIG_SPECIAL     0x4    /* Treat this signal specially. */
  41. #define SIG_NO_TRAP     0x8    /* Signal cannot be trapped. */
  42.  
  43. /* An array of such flags, one for each signal, describing what the
  44.    shell will do with a signal. */
  45. static int sigmodes[NSIG];
  46.  
  47. static void change_signal (), restore_signal ();
  48.  
  49. /* Variables used here but defined in other files. */
  50. extern int interactive_shell, interactive;
  51. extern int interrupt_immediately;
  52. extern int last_command_exit_value;
  53.  
  54. /* The list of things to do originally, before we started trapping. */
  55. SigHandler *original_signals[NSIG];
  56.  
  57. /* For each signal, a slot for a string, which is a command to be
  58.    executed when that signal is recieved.  The slot can also contain
  59.    DEFAULT_SIG, which means do whatever you were going to do before
  60.    you were so rudely interrupted, or IGNORE_SIG, which says ignore
  61.    this signal. */
  62. char *trap_list[NSIG];
  63.  
  64. /* A bitmap of signals received for which we have trap handlers. */
  65. int pending_traps[NSIG];
  66.  
  67. /* A value which can never be the target of a trap handler. */
  68. #define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
  69.  
  70. void
  71. initialize_traps ()
  72. {
  73.   register int i;
  74.  
  75.   trap_list[0] = (char *)NULL;
  76.   sigmodes[0] = SIG_INHERITED;    /* On EXIT trap handler. */
  77.  
  78.   for (i = 1; i < NSIG; i++)
  79.     {
  80.       pending_traps[i] = 0;
  81.       trap_list[i] = (char *)DEFAULT_SIG;
  82.       sigmodes[i] = SIG_INHERITED;
  83.       original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
  84.     }
  85.  
  86.   /* Show which signals are treated specially by the shell. */
  87. #if defined (SIGCHLD)
  88.   original_signals[SIGCHLD] = (SigHandler *) signal (SIGCHLD, SIG_DFL);
  89.   signal (SIGCHLD, original_signals[SIGCHLD]);
  90.   sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
  91. #endif /* SIGCHLD */
  92.  
  93.   original_signals[SIGINT] =
  94.     (SigHandler *) set_signal_handler (SIGINT, SIG_DFL);
  95.   set_signal_handler (SIGINT, original_signals[SIGINT]);
  96.   sigmodes[SIGINT] |= SIG_SPECIAL;
  97.  
  98.   original_signals[SIGQUIT] =
  99.     (SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL);
  100.   set_signal_handler (SIGQUIT, original_signals[SIGQUIT]);
  101.   sigmodes[SIGQUIT] |= SIG_SPECIAL;
  102.  
  103.   if (interactive)
  104.     {
  105.       original_signals[SIGTERM] = (SigHandler *)signal (SIGTERM, SIG_DFL);
  106.       signal (SIGTERM, original_signals[SIGTERM]);
  107.       sigmodes[SIGTERM] |= SIG_SPECIAL;
  108.     }
  109. }
  110.  
  111. /* Return the print name of this signal. */
  112. char *
  113. signal_name (signal)
  114.      int signal;
  115. {
  116.   if (signal >= NSIG)
  117.     return ("bad signal number");
  118.   else
  119.     return (signal_names[signal]);
  120. }
  121.  
  122. /* Turn a string into a signal number, or a number into
  123.    a signal number.  If STRING is "2", "SIGINT", or "INT",
  124.    then (int)2 is returned.  Return NO_SIG if STRING doesn't
  125.    contain a valid signal descriptor. */
  126. int
  127. decode_signal (string)
  128.      char *string;
  129. {
  130.   int sig;
  131.  
  132.   if (sscanf (string, "%d", &sig) == 1)
  133.     {
  134.       if (sig < NSIG && sig >= 0)
  135.     return (sig);
  136.       else
  137.     return (NO_SIG);
  138.     }
  139.  
  140.   for (sig = 0; sig < NSIG; sig++)
  141.     if (STREQ (string, signal_names[sig]) ||
  142.     STREQ (string, &(signal_names[sig])[3]))
  143.       return (sig);
  144.  
  145.   return (NO_SIG);
  146. }
  147.  
  148. /* Non-zero when we catch a trapped signal. */
  149. static int catch_flag = 0;
  150.  
  151. #if !defined (USG) && !defined (USGr4)
  152. #define HAVE_BSD_SIGNALS
  153. #endif
  154.  
  155. void
  156. run_pending_traps ()
  157. {
  158.   register int sig;
  159.   int old_exit_value;
  160.  
  161.   if (catch_flag == 0)        /* simple optimization */
  162.     return;
  163.  
  164.   catch_flag = 0;
  165.  
  166.   /* Preserve $? when running trap. */
  167.   old_exit_value = last_command_exit_value;
  168.  
  169.   for (sig = 0; sig < NSIG; sig++)
  170.     {
  171.       /* XXX this could be made into a counter by using
  172.          while (pending_traps[sig]--) instead of the if statement. */
  173.       if (pending_traps[sig])
  174.     {
  175. #if defined (_POSIX_VERSION)
  176.       sigset_t set, oset;
  177.  
  178.       sigemptyset (&set);
  179.       sigemptyset (&oset);
  180.  
  181.       sigaddset (&set, sig);
  182.       sigprocmask (SIG_BLOCK, &set, &oset);
  183. #else
  184. #  if defined (HAVE_BSD_SIGNALS)
  185.       int oldmask = sigblock (sigmask (sig));
  186. #  endif
  187. #endif /* POSIX_VERSION */
  188.  
  189.       if (sig == SIGINT)
  190.         {
  191.           run_interrupt_trap ();
  192.           interrupt_state = 0;
  193.         }
  194.       else
  195.         parse_and_execute (savestring (trap_list[sig]), "trap", 0);
  196.  
  197.       pending_traps[sig] = 0;
  198.  
  199. #if defined (_POSIX_VERSION)
  200.       sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
  201. #else
  202. #  if defined (HAVE_BSD_SIGNALS)
  203.       sigsetmask (oldmask);
  204. #  endif
  205. #endif /* POSIX_VERSION */
  206.     }
  207.     }
  208.  
  209.   last_command_exit_value = old_exit_value;
  210. }
  211.  
  212. sighandler
  213. trap_handler (sig)
  214.      int sig;
  215. {
  216.   if ((sig >= NSIG) ||
  217.       (trap_list[sig] == (char *)DEFAULT_SIG) ||
  218.       (trap_list[sig] == (char *)IGNORE_SIG))
  219.     programming_error ("trap_handler: Bad signal %d", sig);
  220.   else
  221.     {
  222. #if defined (USG) && !defined (HAVE_BSD_SIGNALS) && !defined (_POSIX_VERSION)
  223.       signal (sig, trap_handler);
  224. #endif /* USG && !HAVE_BSD_SIGNALS && !_POSIX_VERSION */
  225.  
  226.       catch_flag = 1;
  227.       pending_traps[sig]++;
  228.  
  229.       if (interrupt_immediately)
  230.     run_pending_traps ();
  231.     }
  232. #if !defined (VOID_SIGHANDLER)
  233.   return (0);
  234. #endif /* VOID_SIGHANDLER */
  235. }
  236.  
  237. #if defined (JOB_CONTROL) && defined (SIGCHLD)
  238. /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
  239. void
  240. set_sigchld_trap (command_string)
  241.      char *command_string;
  242. {
  243.   void set_signal ();
  244.  
  245.   set_signal (SIGCHLD, command_string);
  246. }
  247.  
  248. /* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current
  249.    SIGCHLD trap handler is DEFAULT_SIG. */
  250. void
  251. maybe_set_sigchld_trap (command_string)
  252.      char *command_string;
  253. {
  254.   void set_signal ();
  255.  
  256.   if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0)
  257.     set_signal (SIGCHLD, command_string);
  258. }
  259. #endif /* JOB_CONTROL && SIGCHLD */
  260.  
  261. static void
  262. set_sigint_trap (command)
  263.      char *command;
  264. {
  265.   void set_signal ();
  266.  
  267.   set_signal (SIGINT, command);
  268. }
  269.  
  270. /* Reset the SIGINT handler so that subshells that are doing `shellsy'
  271.    things, like waiting for command substitution or executing commands
  272.    in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
  273. SigHandler *
  274. set_sigint_handler ()
  275. {
  276.   if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
  277.     return ((SigHandler *)SIG_IGN);
  278.  
  279.   if (sigmodes[SIGINT] & SIG_TRAPPED)
  280.     {
  281.       if (trap_list[SIGINT] == (char *)IGNORE_SIG)
  282.     return ((SigHandler *)SIG_IGN);
  283.       else
  284.     return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
  285.     }
  286.  
  287.   /* The signal is not trapped, so set the handler to the shell's special
  288.      interrupt handler. */
  289.   if (interactive)    /* XXX - was interactive_shell */
  290.     return (set_signal_handler (SIGINT, sigint_sighandler));
  291.   else
  292.     return (set_signal_handler (SIGINT, termination_unwind_protect));
  293. }
  294.  
  295. /* Set SIG to call STRING as a command. */
  296. void
  297. set_signal (sig, string)
  298.      int sig;
  299.      char *string;
  300. {
  301.   /* A signal ignored on entry to the shell cannot be trapped or reset, but
  302.      no error is reported when attempting to do so.  -- Posix.2 */
  303.   if (sigmodes[sig] & SIG_HARD_IGNORE)
  304.     return;
  305.  
  306.   /* Make sure we have original_signals[sig] if the signal has not yet
  307.      been trapped. */
  308.   if ((sigmodes[sig] & SIG_TRAPPED) == 0)
  309.     {
  310.       /* If we aren't sure of the original value, check it. */
  311.       if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
  312.     {
  313.       original_signals[sig] = (SigHandler *)signal (sig, SIG_DFL);
  314.       set_signal_handler (sig, original_signals[sig]);
  315.     }
  316.  
  317.       /* Signals ignored on entry to the shell cannot be trapped or reset. */
  318.       if (original_signals[sig] == SIG_IGN)
  319.     {
  320.       sigmodes[sig] |= SIG_HARD_IGNORE;
  321.       return;
  322.     }
  323.     }
  324.  
  325.   /* Only change the system signal handler if SIG_NO_TRAP is not set.
  326.      The trap command string is changed in either case.  The shell signal
  327.      handlers for SIGINT and SIGCHLD run the user specified traps in an
  328.      environment in which it is safe to do so. */
  329.   if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
  330.     {
  331.       set_signal_handler (sig, SIG_IGN);
  332.       change_signal (sig, savestring (string));
  333.       set_signal_handler (sig, trap_handler);
  334.     }
  335.   else
  336.     change_signal (sig, savestring (string));
  337. }
  338.  
  339. /* If SIG has a string assigned to it, get rid of it.  Then give it
  340.    VALUE. */
  341. static void
  342. change_signal (sig, value)
  343.      int sig;
  344.      char *value;
  345. {
  346.   if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
  347.       (trap_list[sig] != (char *)IGNORE_SIG) &&
  348.       (trap_list[sig] != (char *)DEFAULT_SIG) &&
  349.       (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
  350.     free (trap_list[sig]);
  351.  
  352.   trap_list[sig] = value;
  353.   sigmodes[sig] |= SIG_TRAPPED;
  354. }
  355.  
  356. #define GET_ORIGINAL_SIGNAL(sig) \
  357.     if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
  358.       get_original_signal (sig)
  359.  
  360. static void
  361. get_original_signal (sig)
  362.      int sig;
  363. {
  364.   /* If we aren't sure the of the original value, then get it. */
  365.   if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
  366.     {
  367.       original_signals[sig] =
  368.     (SigHandler *) set_signal_handler (sig, SIG_DFL);
  369.       signal (sig, original_signals[sig]);
  370.  
  371.       /* Signals ignored on entry to the shell cannot be trapped. */
  372.       if (original_signals[sig] == SIG_IGN)
  373.     sigmodes[sig] |= SIG_HARD_IGNORE;
  374.     }
  375. }
  376.  
  377. /* Restore the default action for SIG; i.e., the action the shell
  378.    would have taken before you used the trap command.  This is called
  379.    from trap_builtin (), which takes care to restore the handlers for
  380.    the signals the shell treats specially. */
  381. void
  382. restore_default_signal (sig)
  383.      int sig;
  384. {
  385.   GET_ORIGINAL_SIGNAL (sig);
  386.  
  387.   /* A signal ignored on entry to the shell cannot be trapped or reset, but
  388.      no error is reported when attempting to do so.  Thanks Posix.2. */
  389.   if (sigmodes[sig] & SIG_HARD_IGNORE)
  390.     return;
  391.  
  392.   /* If we aren't trapping this signal, don't bother doing anything else. */
  393.   if (!(sigmodes[sig] & SIG_TRAPPED))
  394.     return;
  395.  
  396.   /* Only change the signal handler for SIG if it allows it. */
  397.   if (!(sigmodes[sig] & SIG_NO_TRAP))
  398.     set_signal_handler (sig, original_signals[sig]);
  399.  
  400.   /* Change the trap command in either case. */
  401.   change_signal (sig, (char *)DEFAULT_SIG);
  402.  
  403.   /* Mark the signal as no longer trapped. */
  404.   sigmodes[sig] &= ~SIG_TRAPPED;
  405. }
  406.  
  407. /* Make this signal be ignored. */
  408. void
  409. ignore_signal (sig)
  410.      int sig;
  411. {
  412.   GET_ORIGINAL_SIGNAL (sig);
  413.  
  414.   /* A signal ignored on entry to the shell cannot be trapped or reset.
  415.      No error is reported when the user attempts to do so.
  416.      Thanks to Posix.2. */
  417.   if (sigmodes[sig] & SIG_HARD_IGNORE)
  418.     return;
  419.  
  420.   /* If already trapped and ignored, no change necessary. */
  421.   if ((sigmodes[sig] & SIG_TRAPPED) && (trap_list[sig] == (char *)IGNORE_SIG))
  422.     return;
  423.  
  424.   /* Only change the signal handler for SIG if it allows it. */
  425.   if (!(sigmodes[sig] & SIG_NO_TRAP))
  426.     signal (sig, SIG_IGN);
  427.  
  428.   /* Change the trap command in either case. */
  429.   change_signal (sig, (char *)IGNORE_SIG);
  430. }
  431.  
  432. /* Handle the calling of "trap 0".  The only sticky situation is when
  433.    the command to be executed includes an "exit".  This is why we have
  434.    to provide our own place for top_level to jump to. */
  435. void
  436. run_exit_trap ()
  437. {
  438.   /* Run the trap only if signal 0 is trapped and not ignored. */
  439.   if ((sigmodes[0] & SIG_TRAPPED) && (trap_list[0] != (char *)IGNORE_SIG))
  440.     {
  441.       char *trap_command = savestring (trap_list[0]);
  442.       int code, old_exit_value;
  443.  
  444.       old_exit_value = last_command_exit_value;
  445.       change_signal (0, (char *)NULL);
  446.       code = setjmp (top_level);
  447.  
  448.       if (code == 0)
  449.     parse_and_execute (trap_command, "trap", 0);
  450.  
  451.       last_command_exit_value = old_exit_value;
  452.     }
  453. }
  454.  
  455. /* Set the handler signal SIG to the original and free any trap
  456.    command associated with it. */     
  457. static void
  458. restore_signal (sig)
  459.      int sig;
  460. {
  461.   set_signal_handler (sig, original_signals[sig]);
  462.   change_signal (sig, (char *)DEFAULT_SIG);
  463.   sigmodes[sig] &= ~SIG_TRAPPED;
  464. }
  465.  
  466. /* Free all the allocated strings in the list of traps and reset the trap
  467.    values to the default. */
  468. void
  469. free_trap_strings ()
  470. {
  471.   register int i;
  472.  
  473.   for (i = 0; i < NSIG; i++)
  474.     {
  475.       if ((sigmodes[i] & SIG_TRAPPED) && trap_list[i] &&
  476.       (trap_list[i] != (char *)IGNORE_SIG) &&
  477.       (trap_list[i] != (char *)DEFAULT_SIG) &&
  478.       (trap_list[i] != (char *)IMPOSSIBLE_TRAP_HANDLER))
  479.     free (trap_list[i]);
  480.       trap_list[i] = (char *)DEFAULT_SIG;
  481.       sigmodes[i] &= ~SIG_TRAPPED;
  482.     }
  483. }
  484.  
  485. /* Reset the handler for SIG to the original value. */
  486. static void
  487. reset_signal (sig)
  488.      int sig;
  489. {
  490.   signal (sig, original_signals[sig]);
  491. }
  492.  
  493. /* Reset the handlers for all trapped signals to the values they had when
  494.    the shell was started. */
  495. void
  496. reset_signal_handlers ()
  497. {
  498.   register int i;
  499.  
  500.   for (i = 0; i < NSIG; i++)
  501.     {
  502.       if (sigmodes[i] & SIG_SPECIAL)
  503.     reset_signal (i);
  504.       else if (sigmodes[i] & SIG_TRAPPED)
  505.     {
  506.       if (trap_list[i] == (char *)IGNORE_SIG)
  507.         signal (i, SIG_IGN);
  508.       else
  509.         reset_signal (i);
  510.     }
  511.     }
  512. }
  513.  
  514. /* Reset all trapped signals to their original values.  Signals set to be
  515.    ignored with trap '' SIGNAL should be ignored, so we make sure that they
  516.    are.  Called by child processes after they are forked. */
  517. void
  518. restore_original_signals ()
  519. {
  520.   register int i;
  521.  
  522.   reset_terminating_signals ();        /* in shell.c */
  523.   for (i = 0; i < NSIG; i++)
  524.     {
  525.       if (sigmodes[i] & SIG_SPECIAL)
  526.     restore_signal (i);
  527.       else if (sigmodes[i] & SIG_TRAPPED)
  528.     {
  529.       if (trap_list[i] == (char *)IGNORE_SIG)
  530.         signal (i, SIG_IGN);
  531.       else
  532.         restore_signal (i);
  533.     }
  534.     }
  535. }
  536.  
  537. /* Run a trap set on SIGINT.  This is called from throw_to_top_level (), and
  538.    declared here to localize the trap functions. */
  539. void
  540. run_interrupt_trap ()
  541. {
  542.   char *command, *saved_command;
  543.   int old_exit_value;
  544.  
  545.   /* Run the interrupt trap if SIGINT is trapped and not ignored, and if
  546.      we are not currently running in the interrupt trap handler. */
  547.   if ((sigmodes[SIGINT] & SIG_TRAPPED) &&
  548.       (trap_list[SIGINT] != (char *)IGNORE_SIG) &&
  549.       (trap_list[SIGINT] != (char *)IMPOSSIBLE_TRAP_HANDLER))
  550.     {
  551.       command = savestring (trap_list[SIGINT]);
  552.  
  553.       old_exit_value = last_command_exit_value;
  554.       saved_command = trap_list[SIGINT];
  555.  
  556.       trap_list[SIGINT] = (char *)IMPOSSIBLE_TRAP_HANDLER;
  557.  
  558.       parse_and_execute (command, "interrupt trap", 0);
  559.  
  560.       if (trap_list[SIGINT] == (char *)IMPOSSIBLE_TRAP_HANDLER)
  561.     trap_list[SIGINT] = saved_command;
  562.  
  563.       last_command_exit_value = old_exit_value;
  564.     }
  565. }
  566.  
  567. /* If a trap handler exists for signal SIG, then call it; otherwise just
  568.    return failure. */
  569. int
  570. maybe_call_trap_handler (sig)
  571.      int sig;
  572. {
  573.   /* Call the trap handler for SIG if the signal is trapped and not ignored. */
  574.   if ((sigmodes[sig] & SIG_TRAPPED) &&
  575.       (trap_list[sig] != (char *)IGNORE_SIG))
  576.     {
  577.       switch (sig)
  578.     {
  579.     case SIGINT:
  580.       run_interrupt_trap ();
  581.       break;
  582.     case 0:
  583.       run_exit_trap ();
  584.       break;
  585.     default:
  586.       trap_handler (sig);
  587.       break;
  588.     }
  589.       return (1);
  590.     }
  591.   else
  592.     return (0);
  593. }
  594.  
  595. int
  596. signal_is_trapped (sig)
  597.      int sig;
  598. {
  599.   return (sigmodes[sig] & SIG_TRAPPED);
  600. }
  601.  
  602. int
  603. signal_is_special (sig)
  604.      int sig;
  605. {
  606.   return (sigmodes[sig] & SIG_SPECIAL);
  607. }
  608.  
  609. void
  610. set_signal_ignored (sig)
  611.      int sig;
  612. {
  613.   sigmodes[sig] |= SIG_HARD_IGNORE;
  614.   original_signals[sig] = SIG_IGN; 
  615. }
  616.